import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'
import store from '@/store'
import { loginConfirm } from '@/util/auth'
import NProgress from 'nprogress'
import { warning, isString } from '@web-utils/core'
import { tfa } from '@/vue/mixin/two-factor-auth'
import { Message, MessageBox } from 'element-ui'
import { isURL } from '@/util/validate'
import { fixPath, iframePath, isFormPath, isNewTabPath, urlToHash } from '@/util/iframe'
import { getStore } from '@/util/store'
import { getObj } from '@/api/admin/sys-public-param'
import { buildRouteNew, useNewStyleRoute } from '@/router/route-convertor'

Vue.use(Router)

NProgress.configure({ showSpinner: false })

NProgress.inc(0.2)

export const createRouter = () => {
  return new Router({ routes })
}

export const paths = []

const router = createRouter()

const onLoadPageError = e => {
  Message.error('页面加载失败，请重试！')
  NProgress.done()
}

export const resetRouter = async () => {
  paths.length = 0
  const newRouter = createRouter()
  router.matcher = newRouter.matcher

  const homeTab = store.state.viewState.tabs.find(value => value.path === '/')
  const homeType = getStore('homeType')
  let res
  if (homeType) {
    res = await getObj(homeType.toUpperCase())
    homeTab.url = res.data.data
  } else {
    homeTab.url = null
  }
}

/**
 * 根据菜单添加路由
 * @param menus
 * @param outerRouter
 */
export const addRouteFromMenu = (menus = [], outerRouter = router) => {
  if (useNewStyleRoute) {
    buildRouteNew(menus, outerRouter)
    return
  }
  const routes = buildRoute(menus, true)
  routes.forEach(route => {
    if (!paths.includes(route.path)) {
      outerRouter.addRoute(route)
      paths.push(route.path)
    }
  })
}

/**
 * 构建路由
 * @param menus
 * @param isTopLevel
 * @returns {*[]}
 */
export const buildRoute = (menus, isTopLevel) => {
  if (menus.length === 0) {
    return []
  }
  const menuProps = {
    label: 'label',
    path: 'path',
    icon: 'icon',
    children: 'children'
  }

  const routes = []

  let acc = 0

  for (let i = 0; i < menus.length; i++) {
    const menuItem = menus[i]

    if (!menuItem.path) {
      menuItem.path = `/${Date.now()}${acc}`
    }

    acc++

    if (isURL(menuItem[menuProps.path])) {
      if (isNewTabPath(menuItem[menuProps.path])) {
        const hash = urlToHash(menuItem[menuProps.path])
        menuItem[menuProps.path] = `/${iframePath}/${hash}`
      }
      continue
    }

    const path = menuItem[menuProps.path]

    // 去掉前导斜杠 / 和路径参数
    const componentFilePath = fixPath(menuItem.path)

    const name = menuItem[menuProps.label]

    const icon = menuItem[menuProps.icon]

    const children = menuItem[menuProps.children]

    const meta = {
      keepAlive: Number(menuItem.keepAlive) === 1,
      icon,
      title: name
    }

    const hasChild = children?.length > 0

    let childRoutes

    if (!hasChild) {
      childRoutes = [
        {
          meta,
          path: '',
          component: () => import(/* webpackChunkName: "r-" */ `../module/${componentFilePath}.vue`)
        }
      ]
    } else {
      childRoutes = buildRoute(children, false)
    }

    const route = {
      path,
      meta,
      component: () => {
        if (isTopLevel) {
          // 判断是否为第一级路由
          return import('@/views/skeleton/Skeleton.vue')
        } else if (hasChild) {
          // 判断是否为多层路由
          return import('@/views/skeleton/Layout.vue')
        } else {
          // 判断是否为最终的页面视图
          return import(/* webpackChunkName: "r-" */ `../module/${componentFilePath}.vue`)
        }
      },
      children: null
    }

    if (isTopLevel || hasChild) {
      route.children = childRoutes
    }

    if (isFormPath(path)) {
      route.props = route => {
        return { ...route.query, ...route.params }
      }
    }

    routes.push(route)
  }

  return routes
}

if (process.env.VUE_APP_OFFLINE !== 'Y') {
  router.beforeEach(async (to, from, next) => {
    NProgress.start()
    if (to.meta.requireLogin === false) {
      next()
    } else {
      const empty = store.state.user.empty
      if (empty) {
        try {
          await store.dispatch('user/getUserInfo')
        } catch (e) {
          warning.call({ $options: { name: 'Auth' } }, e?.message || e)
          next(false)
          NProgress.done()
          return
        }
      }

      if (store.state.common.isLock && to.path !== '/lockApp') {
        next('/lockApp')
        NProgress.done()
        return
      }

      if (store.state.user.tokenValid) {
        if (to.meta.twoFactorAuth === true) {
          await tfa(to, from, next)
          return
        }
        if (empty) {
          // 动态路由需要添加的逻辑,不然从404回到首页有可能需要点两次回到首页
          next(to)
        } else {
          next()
        }
      } else {
        NProgress.done()
        next(false)
        try {
          await loginConfirm(new Error('会话已失效,请重新登录 ！'))
        } catch (e) {
          // warning.call('Auth', e?.message || e)
        }
      }
    }
  })
}

router.afterEach(() => NProgress.done())

router.onError(onLoadPageError)

// 解决 NavigationDuplicated 问题
const originalPush = Router.prototype.push
Router.prototype.push = async function push(location, onResolve, onReject) {
  let path = ''
  if (isString(location)) {
    path = location
  } else {
    path = location.path
  }

  if (store.state.viewState.tabs.length > 100 && !store.state.viewState.tabs.find(value => value.path === path)) {
    await MessageBox.alert('您打开的页面太多了,请关闭一些后重试!', '系统提示', { type: 'warning' })
    onReject?.(Error('打开的页面已达上限,请关闭一些后重试!'))
    return
  }

  if (onResolve || onReject) {
    return originalPush.call(this, location, onResolve, () => onReject?.(null))
  }
  return originalPush.call(this, location).catch(err => err)
}

export default router
